#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>

#define DEV_NMAE "/dev/fb0"

#define HELLO_DBG
#ifdef HELLO_DBG
#define hello_dbg(fmt, ...) printf("[%s][%d]" fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__)
#else
#define hello_dbg(fmt, ...)
#endif

int main(int argc, char *argv[])
{
    int fd;
    int ret;
    struct fb_var_screeninfo var;
    unsigned char *fb_map;
    size_t fb_size;

    hello_dbg("%s, %s", __DATE__, __TIME__);

    fd = open(DEV_NMAE, O_RDWR);
    if (fd < 0)
    {
        hello_dbg("open %s error, erron:%d:%s", DEV_NMAE, errno, strerror(errno));
        return -errno;
    }

    ret = ioctl(fd, FBIOGET_VSCREENINFO, &var);
    if (ret < 0)
    {
        hello_dbg("get fb v screen iofo error:%d:%s", errno, strerror(errno));
        close(fd);
        return -errno;
    }
    fb_size = var.xres * var.yres * var.bits_per_pixel / 8;
    hello_dbg("v screen iofo:%d, %d, %d, %d", var.xres, var.yres, var.bits_per_pixel, fb_size);

    fb_map = (unsigned char *)mmap(NULL, fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (fb_map == (unsigned char *)MAP_FAILED)
    {
        hello_dbg("fb mmap error:%d:%s", errno, strerror(errno));
        close(fd);
        return -errno;
    }

#define LCD_RED (0xf800)
#define LCD_GREEN (0x07e0)
#define LCD_BLUE (0x001f)
#define LCD_WHITE (0xffff)
#define LCD_BLACK (0x0000)
#define LCD_YELLOW (0x0FFE)
#define LCD_GRAY0 (0xEF7D)
#define LCD_GRAY1 (0x8410)
#define LCD_GRAY2 (0x4208)

    uint16_t color_num[] = {
        LCD_RED,
        LCD_GREEN,
        LCD_BLUE,
        LCD_WHITE,
        LCD_BLACK,
        LCD_YELLOW,
        LCD_GRAY0,
        LCD_GRAY1,
        LCD_GRAY1,
    };

    uint8_t *buf = malloc(fb_size);

    memset(fb_map, 0xff, fb_size);

    hello_dbg("");

    uint8_t show_cnt = 0;
    while (show_cnt < sizeof(color_num) / sizeof(color_num[0]))
    {
        sleep(1);

        uint16_t color = color_num[show_cnt];
        for (size_t i = 0; i < fb_size / 2; i++)
        {
            buf[i * 2] = (color >> 8) & 0xff;
            buf[i * 2 + 1] = (color)&0xff;
        }
        hello_dbg("fb set color %d:0x%04x, 0x%02x%02x", show_cnt, color, buf[0], buf[1]);
        memcpy(fb_map, buf, fb_size);

        // uint8_t color = (0x01 << show_cnt) % 0xff + (0x11 << show_cnt) % 0x0f;
        // memset(fb_map, color, fb_size);

        show_cnt++;
    }

    hello_dbg("");

    free(buf);
    munmap(fb_map, fb_size);
    close(fd);

    return 0;
}
